﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BreukADO.Model
{

    struct Breuk : IComparable<Breuk>
    {

        private int teller;
        private int noemer;
        private static Random random = new Random();

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="teller">Teller</param>
        /// <param name="noemer">Noemer</param>
        public Breuk(int teller, int noemer)
        {
            this.teller = 0;
            this.noemer = 0;
            if (noemer != 0)
            {
                this.teller = teller;
                this.noemer = noemer;
            }
        }

        /// <summary>
        /// Statische methode om random breuken te maken
        /// </summary>
        /// <param name="min">Minimum (ondergrens)</param>
        /// <param name="max">Maximum (bovengrens)</param>
        /// <returns>Breuk</returns>
        public static Breuk RandomBreuk(int min, int max)
        {
            int newTeller = random.Next(min, max);
            int newNoemer = random.Next(min, max);
            while (newNoemer == 0) newNoemer = random.Next(min, max);
            return new Breuk(newTeller, newNoemer);
        }

        /// <summary>
        /// Default CompareTo-methode
        /// Indien het object een breuk-object is wordt er vergeleken op basis van het resultaat (teller/noemer).
        /// </summary>
        /// <param name="obj">Breuk-object</param>
        /// <returns>integer</returns>
        public int CompareTo(Breuk breuk)
        {
            return Convert.ToInt32(this.Decimaal() - breuk.Decimaal());
        }

        /// <summary>
        /// Operator +
        /// </summary>
        /// <param name="b1">Breuk</param>
        /// <param name="b2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk operator +(Breuk b1, Breuk b2)
        {
            int noemer1 = b1.noemer;
            int noemer2 = b2.noemer;

            if (b1.noemer != b2.noemer)
            {
                b2.teller = b2.teller * noemer1;
                b2.noemer = b2.noemer * noemer1;

                b1.teller = b1.teller * noemer2;
                b1.noemer = b1.noemer * noemer2;
            }
            Breuk b = new Breuk(b1.teller + b2.teller, b1.noemer);
            b1.Vereenvoudig();
            b2.Vereenvoudig();
            b.Vereenvoudig();
            return b;
        }

        /// <summary>
        /// Methode om breuken op te tellen
        /// </summary>
        /// <param name="breuk1">Breuk</param>
        /// <param name="breuk2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk TelOp(Breuk breuk1, Breuk breuk2)
        {
            return breuk1 + breuk2;
        }

        /// <summary>
        /// Operator -
        /// </summary>
        /// <param name="b1">Breuk</param>
        /// <param name="b2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk operator -(Breuk b1, Breuk b2)
        {
            int noemer1 = b1.noemer;
            int noemer2 = b2.noemer;

            if (b1.noemer != b2.noemer)
            {
                b2.teller = b2.teller * noemer1;
                b2.noemer = b2.noemer * noemer1;

                b1.teller = b1.teller * noemer2;
                b1.noemer = b1.noemer * noemer2;
            }
            Breuk b = new Breuk(b1.teller - b2.teller, b1.noemer);
            b1.Vereenvoudig();
            b2.Vereenvoudig();
            b.Vereenvoudig();
            return b;
        }

        /// <summary>
        /// Methode om breuken af te trekken
        /// </summary>
        /// <param name="breuk1">Breuk</param>
        /// <param name="breuk2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk TrekAf(Breuk breuk1, Breuk breuk2)
        {
            return breuk1 - breuk2;
        }

        /// <summary>
        /// Operator *
        /// </summary>
        /// <param name="b1">Breuk</param>
        /// <param name="b2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk operator *(Breuk b1, Breuk b2)
        {
            Breuk b = new Breuk(b1.teller * b2.teller, b1.noemer * b2.noemer);
            b.Vereenvoudig();
            return b;
        }

        /// <summary>
        /// Methode om breuken te vermenigvuldigen
        /// </summary>
        /// <param name="breuk1">Breuk</param>
        /// <param name="breuk2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk Vermenigvuldig(Breuk breuk1, Breuk breuk2)
        {
            return breuk1 * breuk2;
        }

        /// <summary>
        /// Operator /
        /// </summary>
        /// <param name="b1">Breuk</param>
        /// <param name="b2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk operator /(Breuk b1, Breuk b2)
        {
            Breuk b = new Breuk(b1.teller * b2.noemer, b1.noemer * b2.teller);
            b.Vereenvoudig();
            return b;
        }

        /// <summary>
        /// Methode om breuken te delen
        /// </summary>
        /// <param name="breuk1">Breuk</param>
        /// <param name="breuk2">Breuk</param>
        /// <returns>Breuk</returns>
        public static Breuk Delen(Breuk breuk1, Breuk breuk2)
        {
            return breuk1 / breuk2;
        }

        /// <summary>
        /// Methode om breuken te vereenvoudigen
        /// </summary>
        public void Vereenvoudig()
        {
            int g = Ggd();

            teller /= g;
            noemer /= g;
        }

        /// <summary>
        /// Methode om de breuk te tonen als string
        /// </summary>
        /// <returns>String</returns>
        public String Toon()
        {
            String res;
            if (noemer == 1)
            {
                res = "" + teller;
            }
            else if (noemer < 0)
            {
                if (teller > 0)
                {
                    res = (0 - Math.Abs(teller)) + "/" + (0 + Math.Abs(noemer));
                }
                else
                {
                    res = Math.Abs(teller) + "/" + (Math.Abs(noemer));
                }

            }
            else
            {
                res = teller + "/" + noemer;
            }
            return res;

        }

        /// <summary>
        /// Methode om een breuk als decimaal getal met bepaalde precisie te tonen
        /// </summary>
        /// <param name="p">Precisie (integer)</param>
        /// <returns>String</returns>
        public String ToonDecimaal(int p)
        {
            String format = "{0:0.";
            for (int i = 0; i < p; i++)
            {
                format += "0";
            }
            format += "}";

            return String.Format(format, Decimaal());
        }

        /// <summary>
        /// Decimale uitkomst van de breuk
        /// </summary>
        /// <returns>double</returns>
        public double Decimaal()
        {
            return ((double)teller) / ((double)noemer);
        }

        /// <summary>
        /// Methode om de Grootste Gemene Deler (GGD) te berekenen
        /// </summary>
        /// <returns>integer</returns>
        public int Ggd()
        {
            int a = teller;
            int b = noemer;
            while (b != 0)
            {
                int rest = a % b;
                a = b;
                b = rest;
            }
            return a;
        }

        /// <summary>
        /// Methode om een Breuk te maken van de input string
        /// </summary>
        /// <param name="input">Breuk string</param>
        /// <returns>Breuk</returns>
        public static Breuk StringToBreuk(string input)
        {
            string[] d = input.Split('/');
            return new Breuk(Int32.Parse(d[0]), Int32.Parse(d[1]));
        }

        /// <summary>
        /// Methode om een string weer te geven
        /// </summary>
        /// <returns>String</returns>
        override public String ToString()
        {
            return teller + "/" + noemer;
        }


        /// <summary>
        /// Getter & Setter voor Teller
        /// </summary>
        public int Teller
        {
            get { return teller; }
            set { teller = value; }
        }

        /// <summary>
        /// Getter & Setter voor Noemer
        /// </summary>
        public int Noemer
        {
            get { return noemer; }
            set { noemer = value; }
        }

    }
}
